<?php

namespace Api\Openapi;


use S\Http;
use S\Config;

/**
 * Class Pay
 * @package Api\Openapi
 * @description 交易服务类
 *
 * 使用示范：
 *
 * I 实时代扣
 *
 * $sdk = new \Api\Openapi\Pay();
 * $result_trans_id = $sdk->deduce(
 *     \Api\Openapi\Pay::SERVICE_JINTONG,  //支付服务方名称，此处使用金通示范
 *     \S\Util\Genuid::getOrderId("")",  //交易id, 不超过20位数字
 *     date("Y-m-d H:i:s"),  //交易时间
 *     \Api\Openapi\Pay::CERT_TYPE_ID_CARD,  //支付方证件类型
 *   　"500222199107131659",  //支付方姓名
 *     "郑麒麟",  //支付方证件号码
 *     "6217230200001546524",  // 支付方支付账号
 *     $mer_id,  //商户号，使用金通支付时必需，向产品申请
 *     1,  //支付金额，此处使用1分示范
 *     "教育贷",  //支付原因，使用金通支付时必送
 *     \Api\Openapi\Pay::CARD_TYPE_DEBIT,  //账号类型，此处使用借记卡示范
 *     \Api\Openapi\Pay::BIZ_TYPE_LOAN,  //交易类型，此处使用小贷示范
 * );
 */
class Pay {

    const URI_PAY_DEDUCE = "/pay/deduce";  //实时代扣
    const URI_PAY_WITHDRAW = "/pay/withdraw";  //实时代付
    const URI_PAY_QUERY_TRANS_RESULT = "/pay/query";  //代扣|代收交易结果查询
    const URI_PAY_QUERY_WHITELIST = "/pay/whitelist/query";  //白名单查询
    const URI_PAY_SUBMIT_WHITELIST = "/pay/whitelist/submit";  //白名单登记
    const URI_PAY_AUTHORIZE = '/pay/authorize';

    const SERVICE_JINTONG = "jintong";  //金通支付
    const SERVICE_KUAIQIAN = "kuaiqian";  //快钱支付
    const SERVICE_YINSHENG = "yinsheng";  //银盛支付
    const SERVICE_ZHONGJIN = "zhongjin";  //中金支付

    const CARD_TYPE_DEBIT = "0";  //借记卡
    const CARD_TYPE_DEPOSIT_BOOK = "1";  //存折
    const CARD_TYPE_CREDIT = "2";  //贷记卡
    const CARD_TYPE_ORG_ACCT = "3";  //公司账号

    const BIZ_TYPE_FUND = "01";  //基金
    const BIZ_TYPE_LOAN = "02";  //小贷
    const BIZ_TYPE_INSURANCE = "03";  //保险
    const BIZ_TYPE_ASSET_MANAGEMENT = "04";  //资管
    const BIZ_TYPE_ETC = "05";  //其他

    const CERT_TYPE_ID_CARD = "01";  //证件类型－身份证

    const TRANS_TYPE_WITHDRAW = "01";  //代收
    const TRANS_TYPE_DEDUCE = "02";  //代收
    const TRANS_TYPE_PAY = "03";  //支付

    const RESP_STATUS_SUCC = 0;
    const RESP_STATUS_HANDLING = 1;
    const RESP_STATUS_FAIL = 2;

    private $_trans_detail = array();

    /**
     * 实时代扣
     *
     * @param string $service 支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $trans_id 交易id，必送，用于未来对账
     * @param string $trans_timestamp 交易时间戳，必送，保证支付双方一致(e.g. 使用time()生成的时间戳)
     * @param string $cert_type 支付方证件类型(参考本类中常量 e.g. 身份证 self::CERT_TYPE_ID_CARD)
     * @param string $cert_no 支付方证件号码
     * @param string $name 支付方姓名
     * @param string $acct 支付方支付账号
     * @param int $amt 支付金额，以分作为最小单位计算：e.g 125.30 元 = 12530 分
     * @param array $options default array() 代付选项，根据支付服务方上送不同值，
     *                                       详情参考：@link http://wiki.i.beebank.com/pages/viewpage.action?pageId=6619448
     * @param int $timeout default 10000
     *
     * @return array|bool 交易成功返回：
     *                        serial_no     string 商户交易id        must
     *                        trans_serial_no string 支付平台交易id   optional
     *                        trans_time    string 交易时间          must
     *                        amt           int    交易金额(单位为分)  optional
     *                        status        int    交易状态(0-成功 1-处理中 2-失败)   optional
     *                    失败返回false
     * @throws \S\Exception
     */
    public function deduce($service, $trans_id, $trans_timestamp, $cert_type, $cert_no, $name, $acct, $amt, array $options = array(), $timeout = 10000) {
        $body = array(
            "service" => $service,
            "trans_id" => $trans_id,
            "trans_time" => $trans_timestamp,
            "cert_type" => $cert_type,
            "cert_no" => $cert_no,
            "name" => $name,
            "acct" => $acct,
            "amt" => $amt,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $trans_info = Util::request(self::URI_PAY_DEDUCE, $params, $timeout)["body"];

        return $trans_info;
    }

    /**
     * 查询实时代扣信息
     * @param string $service        支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $ori_trans_id default null    用户流水号
     * @param string $trans_id default null        平台流水号
     * @param array $options              default array() 查询选项，根据支付服务方上送不同值，
     * @param int $timeout default 10000
     * @return array     未查询到返回array()，查询成功返回:
     *                                          trans_time      string 交易时间
     *                                          serial_no       string 商户交易id
     *                                          trans_serial_no string 平台交易id
     *                                          trans_type      string 交易类型 01-代付 02-代扣
     *                                          amt             int    交易金额
     *                                          status          int    交易状态  0-成功 1-处理中 2-失败
     */
    public function queryDeduceTransDetail($service, $ori_trans_id = null, $trans_id = null, array $options = array(), $timeout = 10000) {
        $body = array(
            "service" => $service,
            "ori_trans_id" => $ori_trans_id,
            "trans_id" => $trans_id,
            "trans_type" => self::TRANS_TYPE_DEDUCE,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $this->_trans_detail = Util::request(self::URI_PAY_QUERY_TRANS_RESULT, $params, $timeout)["body"];

        return $this->_trans_detail;
    }

    /**
     * 实时代付
     *
     * 适用于用户提现场景
     *
     * @param string $service 支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $trans_id 交易id，必送，用于未来对账
     * @param string $trans_timestamp 交易时间戳，必送，保证支付双方一致(e.g. 使用time()生成的时间戳)
     * @param string $name 收款方姓名
     * @param string $acct 收款方账号
     * @param int $amt 支付金额，以分作为最小单位计算：e.g 125.30 元 = 12530 分
     * @param array $options default array() 代付选项，根据支付服务方上送不同值，
     *                                       详情参考：@link http://wiki.i.beebank.com/pages/viewpage.action?pageId=6619412
     * @param int $timeout default 15000
     *
     * @return array|bool 交易成功返回：
     *                        serial_no 商户交易id
     *                        trans_serial_no 支付平台交易id
     *                        trans_time 交易时间
     *                    失败返回false
     * @throws \S\Exception
     */
    public function withdraw($service, $trans_id, $trans_timestamp, $name, $acct, $amt, array $options = array(), $timeout = 15000) {
        $body = array(
            "service" => $service,
            "trans_id" => $trans_id,
            "trans_time" => $trans_timestamp,
            "name" => $name,
            "acct" => $acct,
            "amt" => $amt,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $trans_info = Util::request(self::URI_PAY_WITHDRAW, $params, $timeout)["body"];

        return $trans_info;
    }

    /**
     * 查询代付交易结果详情
     *
     * @param string $service 支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $ori_trans_id default null   用户流水号
     * @param string $trans_id default null       平台流水号
     * @param array $options default array() 查询选项，根据支付服务方上送不同值，
     *                                       详情参考：@link http://wiki.i.beebank.com/pages/viewpage.action?pageId=6619452
     * @param int $timeout default 15000
     *
     * @return array 未查询到返回array()，查询成功返回:
     *                                          trans_time  string 交易时间
     *                                          serial_no   string 商户交易id
     *                                          trans_serial_no string 平台交易id
     *                                          trans_type  string 交易类型 01-代付 02-代扣
     *                                          amt         int    交易金额
     *                                          status      int    交易状态  0-成功 1-处理中 2-失败
     */
    public function queryWithdrawTransDetail($service, $ori_trans_id = null, $trans_id = null, array $options = array(), $timeout = 15000) {
        $body = array(
            "service" => $service,
            "ori_trans_id" => $ori_trans_id,
            "trans_id" => $trans_id,
            "trans_type" => self::TRANS_TYPE_WITHDRAW,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $this->_trans_detail = Util::request(self::URI_PAY_QUERY_TRANS_RESULT, $params, $timeout)["body"];

        return $this->_trans_detail;
    }

    /**
     * 判断是否为支付服务方白名单
     *
     * @param string $service 支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $card_no 支付账号
     * @param array $options 查询选项，根据支付服务方上送不同值，
     *                       详情参考：@link http://wiki.i.beebank.com/pages/viewpage.action?pageId=6619462
     * @param int $timeout default 15000
     *
     * @return array    : status 0-失败 1-成功
     *                    msg    说明
     */
    public function isWhitelist($service, $card_no, array $options = array(), $timeout = 15000){
        $body = array(
            "service" => $service,
            "card_no" => $card_no,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $this->_trans_detail = Util::request(self::URI_PAY_QUERY_WHITELIST, $params, $timeout)["body"];

        return $this->_trans_detail;
    }

    /**
     * 添加支付服务方白名单
     *
     * @param string $service 支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_JINTONG
     * @param string $card_no 银行账号
     * @param string $card_type 银行账号类型 0-借记卡(默认) 1-存折 2-贷记卡 3-公司账号
     * @param string $cert_type 证件类型(e.g. 身份证 self::CERT_TYPE_ID_CARD)
     * @param string $cert_no 证件号码
     * @param string $name 姓名
     * @param array $options 查询选项，根据支付服务方上送不同值，
     *                       详情参考：@link http://wiki.i.beebank.com/pages/viewpage.action?pageId=6619462
     * @param int $timeout default 15000
     *
     * @return bool
     */
    public function submitWhitelist($service, $card_no, $card_type, $cert_type, $cert_no, $name, array $options = array(), $timeout = 15000){
        $body = array(
            "service" => $service,
            "card_no" => $card_no,
            "card_type" => empty($card_type)?self::CARD_TYPE_DEBIT:$card_type,
            "cert_type" => $cert_type,
            "cert_no" => $cert_no,
            "name" => $name,
            "options" => $options,
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $this->_trans_detail = Util::request(self::URI_PAY_SUBMIT_WHITELIST, $params, $timeout)["body"];

        return $this->_trans_detail;
    }

    /**
     * 短信验证
     *
     * @param string $service       支付服务方名称，参考在本类中定义常量：e.g. \Api\Openapi\Pay::SERVICE_KUAIQIAN
     * @param string $mobile        手机号
     * @param string $card_no       银行卡账号
     * @param string $cert_type     证件类型(e.g. 身份证 self::CERT_TYPE_ID_CARD)
     * @param string $cert_no       证件号
     * @param string $name          姓名
     * @param array $options        查询选项，根据支付服务方上送不同值，
     *                              array(
     *                                  'ori_trans_id'  string  M  商户流水号
     *                                  'mer_id'        string  M  商户号 e.g. 'mer_id_qianlong_recharge'
     *                                  'cust_id'       string  M  客户号
     *                                  'amt'           int     M  交易金额(单位为分) e.g. 1010 = 10.10元
     *                                  'expire_date'   string  O  信用卡的有效期, 4位定长数字字符, 格式为MMYY e.g. 1007 = 2007年10月
     *                                  'cvv2'          string  O  安全校验值, 3位定长数字字符, 对于银联和 VISA 卡,对应卡片背面的 CVV2 数字;对于 MasterCard 卡,对应卡片背面的 CVC2 数字
     *                              );
     * @param int $timeout default 20000
     * @return array              成功返回 array(
     *                               'merchantId'  string  商户编号  15位字母和数字字符串
     *                               'customerId'  string  客户号
     *                               'storablePan' string  缩略卡号  卡号前6位+后4位组成的10位数字字符串
     *                               'token'       string  手机验证码令牌
     *                               'status'      int     0-成功 1-处理中 2-失败
     *                               'ori_trans_id' string 请求时送入的商户流水号
     *                             );
     */
    public function authorize($service, $mobile, $card_no, $cert_type, $cert_no, $name, array $options, $timeout = 20000){
        $body = array(
            'service' => $service,
            'mobile' => $mobile,
            'cert_type' => $cert_type,
            'cert_no' => $cert_no,
            'name' => $name,
            'acct' => $card_no,
            'options' => $options
        );
        $params = array(
            "header" => array(),
            "body" => $body,
        );

        $this->_trans_detail = Util::request(self::URI_PAY_AUTHORIZE, $params, $timeout)["body"];

        return $this->_trans_detail;
    }

    /**
     * 校验签名
     *
     * @param array $params
     * @return bool  成功返回true 失败返回false
     */
    public static function checkSign(array $params = array()){
        $time = $params['time'];
        $key = $params['key'];
        $m = $params['m'];
        unset($params['time']);
        unset($params['key']);
        unset($params['m']);

        $app_secret = Config::confSecurity("openapi.app_secret");
        if($params){
            ksort($params);
            $encodeFieldValue = array_values($params);
            $encodeFieldValue = implode("",$encodeFieldValue);
        }else{
            $encodeFieldValue = '';
        }

        $_m = md5($key."|".$time."|".$app_secret."|".$encodeFieldValue);

        return ($m == $_m);
    }
}